home *** CD-ROM | disk | FTP | other *** search
/ The Games Machine 76 / XENIATGM66.iso / Indiana Jones / Indiana Jones.exe / RESOURCE / PREVIEW.GOB / cog_aet_marduk.cog < prev    next >
Text File  |  1999-11-15  |  28KB  |  1,138 lines

  1. # Jones 3D Cog Script
  2. #
  3. # aet_Marduk.cog
  4. #
  5. # [SCHOLL]
  6. #
  7. # (C) 1999 LucasArts Entertainment Co. All Rights Reserved
  8. # ========================================================================================
  9. symbols
  10.     
  11. message     startup
  12. message        aievent
  13. message        timer
  14. message        callback
  15. message        user0
  16. message        touched
  17. message        damaged
  18. message        pulse
  19. message        blocked
  20.  
  21.  
  22. thing        t_Marduk                    mask=0x0 # I'm capturing this 
  23. thing        probe                        # Charging probe from ceiling.
  24. cog            Aet_MardukDias        
  25. thing        t_baseThing
  26.  
  27. # ************************** MARDUK VARS *******************
  28.  
  29. vector        v_BasePos            local    # Center of opening that Marduk hovers above
  30. vector        v_ChargingPos        local    # Center of opening that Marduk hovers above
  31. vector        v_DestPos            local
  32. vector        v_MardukPos            local
  33. vector        v_BaseToMarduk        local
  34. vector        v_MardukLook        local
  35.  
  36. int            n_MardukOctant        local
  37. int            n_MardukFaceDir        local
  38. int            n_MaxOctChange        local
  39. int            n_DirToIndy            local
  40. int            n_Ammo=0            local
  41. int            e_Mode                local
  42. template    tpl_CrntWeapon        local
  43. int            b_AttackLow            local    # if true attack only from low height, false attack only from high height
  44. int            b_MardukLow                local     # true is currently flying low
  45. int            n_TimesBeenHit=0        local    # number of times marduk has been hit by a reflected lightning ball
  46.  
  47.     
  48. int            n_MoveSoundChannel=-1        local  
  49. vector        v_MardukVel                local
  50. flex        f_MardukVelMag            local
  51. flex        MIN_MOVE_VOL=0.4        local
  52. flex        MAX_MOVE_VOL=1.0        local
  53. flex        VEL_VOL_MUL=1.2            local
  54. flex        f_MoveVol                local
  55. flex        MIN_MOVE_PITCH=0.9        local
  56. flex        MAX_MOVE_PITCH=1.0        local
  57. flex        VEL_PITCH_MUL=0.4        local
  58. flex        f_MovePitch                local
  59. flex        UPDATE_MOVE_VOL_PULSE=0.25    local
  60.  
  61. int            MAX_HITS=5            local # when marduk has been hit this many times he will flee
  62.  
  63. flex        DEFAULT_MOVE_SPEED=1.0 local
  64. flex        FURY_MOVE_SPEED=2.5 local
  65.  
  66. int            n_ShockLightAnim=-1        local
  67. flex        SHOCK_LIGHT_DURATION=0.25    local
  68.     
  69.  
  70. vector        v_Up                local
  71. vector        v_Right                local
  72. vector        v_North                local
  73. vector        v_East                local
  74.  
  75. vector        v_Oct0                local
  76. vector        v_Oct1                local
  77. vector        v_Oct2                local
  78. vector        v_Oct3                local
  79. vector        v_Oct4                local
  80. vector        v_Oct5                local
  81. vector        v_Oct6                local
  82. vector        v_Oct7                local
  83.  
  84.  
  85. # ************************** INDY VARS *******************
  86.  
  87. thing        t_Indy                local
  88. vector        v_IndyPos            local
  89. vector        v_BaseToIndy        local
  90. int            n_IndyOctant        local
  91. int            b_IndyLow            local     # true if Indy is currently on or near floor
  92.  
  93. int            b_OKToDamageIndy=1                local
  94.  
  95.  
  96. # ************************** LIGHTNING VARS *******************
  97. vector        v_LightningSrcOffset        local    # offset from probe to start lightning
  98. vector        v_LightningEndPos            local    
  99.  
  100. flex        LIGHTNING_HEAD_DEST_UP_OFFSET=0.17        local          #offset from marduk pos to head along up
  101. flex        LIGHTNING_WING_DEST_RIGHT_OFFSET=0.025        local          #offset from marduk pos to wing along right
  102. flex        LIGHTNING_WING_DEST_UP_OFFSET=0.1        local          #offset from marduk pos to wing along right
  103. flex        LIGHTNING_DURATION=1.7                local
  104. flex        LIGHTNING_START_DELAY=1.0            local    #delay from start of charge animation
  105. flex        LIGHTNING_BASE_RADIUS=0.1            local
  106. flex        LIGHTNING_TIP_RADIUS=0.05            local
  107.  
  108. vector        v_MinLight                            local 
  109. vector        v_MaxLight                            local 
  110. int            n_ProbeLightAnim=-1                    local
  111.  
  112.  
  113. # ************************** MISC LOCAL VARS *******************
  114.  
  115. int            n_OctDist                local
  116. int            n_eventType                local
  117. int            n_Track                    local
  118. int            n_TimerID                local
  119. int            n_TempInt                local
  120. int            b_TempBool                local
  121. vector        v_TempVec                local
  122. flex        f_TempFlex                local
  123. flex        f_Dot                    local 
  124. flex        f_Dot1                    local 
  125. flex        f_Dist                    local
  126.  
  127.  
  128. # ************************** MARDUK MODES *******************
  129.  
  130. int            HOVERING_MODE=0                local
  131.  
  132. int            MOVING_MODE=1                local
  133. int            FIRING_MODE=2                local
  134. int            HOVERING_NO_FIRE_MODE=3        local
  135. int            FURY_MODE=4                    local
  136. int            CHARGING_MODE=5                local
  137. int            MOVING_TO_CHARGING_POS_MODE=6 local
  138. int            DO_NOTHING_MODE=7             local
  139.  
  140. # ************************** TIMER IDS *******************
  141.  
  142. int            TIMER_ID_MOVE=0            local
  143. int            TIMER_ID_ATTACK_DONE=1            local
  144. int            TIMER_ID_ATTACK_OKAY=2            local
  145. int            TIMER_ID_START_LIGHTING=3        local
  146. int            TIMER_ID_STOP_PROBE_LIGHT=4        local
  147. int            TIMER_ID_CHARGE_COMPLETE=5        local
  148. int            TIMER_ID_REEVALUATE=6        local
  149. int            TIMER_ID_STOP_FURY=7            local
  150. int            TIMER_ID_STOP_SHOCK_LIGHT=8        local
  151. int            TIMER_ID_START_FURY=9            local
  152. int            TIMER_ID_CHARGE_SPARKS=10        local
  153.  
  154.  
  155. # ************************** MISC CONSTANTS *******************
  156.  
  157. flex        MARDUK_MOVE_RADIUS=0.475    local
  158.  
  159. flex        ATTACK_TIME=3.0                        local
  160. flex        DELAY_BEFORE_ATTACK_AFTER_MOVE=0.01 local
  161. flex        AFTER_ATTACK_DELAY=0.01                local
  162. flex        FURY_DURATION=2.0                    local
  163. flex        FURY_START_DELAY=1.75                local
  164. flex        CHARGE_SPARK_DELAY=0.3                local
  165.  
  166. int            MAX_AMMO=5                        local    
  167. flex        CHARGE_DURATION=4.0                local
  168.  
  169. flex        HIGH_HEIGHT_ADJUST=0.30            local  
  170.  
  171.  
  172. # ************************** SOUNDS *******************
  173.  
  174. sound        shock=aet_mr_hit_indy.wav        local
  175. sound        chargeup=aet_mr_chargeup.wav    local
  176. sound        fly=aet_mr_fly.wav                local
  177. sound        defeat=aet_mr_defeat.wav        local
  178. sound        rebound=aet_mr_ball_rebound.wav local    #load so that engine can play it. 
  179. sound        hurt=aet_mr_damaged.wav            local
  180. sound        rico=gen_ricochet_boss.wav        local
  181.  
  182. template    tpl_ChargeSparks=mardukCharge                    local
  183.  
  184. # ************************** SUBROUTINES *******************
  185. flex    MoveToNewPosition        local
  186. flex    MoveToChargingPos        local
  187. flex    Charge                    local
  188. flex    Set_b_Low                local
  189. flex    ComputeMardukOctant        local
  190. flex    ComputeIndyOctant        local
  191.  
  192. end
  193.  
  194. # ========================================================================================
  195. code
  196.  
  197. startup:
  198.     v_Up = VectorSet(0.0, 0.0, 1.0);
  199.     v_North = VectorSet(0.0, 1.0, 0.0);
  200.     v_East = VectorSet(1.0, 0.0, 0.0);
  201.     
  202.     v_Oct0 = VectorSet(0.38, 0.92, 0.0);
  203.     v_Oct1 = VectorSet(0.92, 0.38, 0.0);
  204.     v_Oct2 = VectorSet(0.92, -0.38, 0.0);
  205.     v_Oct3 = VectorSet(0.38, -0.92, 0.0);
  206.     v_Oct4 = VectorSet(-0.38, -0.92, 0.0);
  207.     v_Oct5 = VectorSet(-0.92, -0.38, 0.0);
  208.     v_Oct6 = VectorSet(-0.92, 0.38, 0.0);
  209.     v_Oct7 = VectorSet(-0.38, 0.92, 0.0);
  210.  
  211.     return;
  212.     
  213. user0:
  214.     // Initialize for combat
  215.     CaptureThing(t_Marduk); // so I get all the messages I need
  216. //    DebugPrint("User0");
  217.     t_Indy = GetLocalPlayerThing();
  218.     tpl_CrntWeapon    = GetActorWeapon(t_Marduk);            # save off base weapon setting
  219.  
  220.     v_ChargingPos = GetThingPos(t_baseThing);
  221. //    v_ChargingPos = VectorSet(0.20, 0.199, 5.525); // A ghost object location would be a better choice
  222. //    v_ChargingPos = VectorAdd(v_ChargingPos, VectorScale(v_Up, 0.22));
  223.     v_BasePos = GetThingPos(t_baseThing);
  224. //    v_BasePos = VectorSet(0.20, 0.199, 5.525); // A ghost object location would be a better choice
  225. //    v_BasePos = VectorAdd(v_BasePos, VectorScale(v_Up, 0.22));
  226. //    SetCollideType(t_Marduk, 0);
  227. //    MoveThingToPos(t_Marduk, v_BasePos, 0.0);
  228. //    SetCollideType(t_Marduk, 1);
  229.  
  230.     AISetMoveSpeed(t_Marduk, DEFAULT_MOVE_SPEED);
  231.     b_AttackLow = 1;
  232.     call Charge;
  233.     
  234.     n_MoveSoundChannel = PlaySoundThing(fly, t_Marduk, 1.0, 0.0, 20.0, 0x881);
  235.     SetPulse(UPDATE_MOVE_VOL_PULSE);
  236.  
  237.     return;
  238.  
  239. # ........................................................................................
  240. // Adjust volume of move sound based on velocity
  241. pulse:
  242.     if (n_MoveSoundChannel != -1)
  243.     {
  244.         v_MardukVel = GetThingVel(t_Marduk);
  245.         f_MardukVelMag = VectorLen(v_MardukVel);
  246. //        DebugFlex(f_MardukVelMag, "Vel");
  247.         f_MoveVol = (VEL_VOL_MUL * f_MardukVelMag) + MIN_MOVE_VOL;
  248.         if (f_MoveVol > MAX_MOVE_VOL)
  249.         {
  250.             f_MoveVol = MAX_MOVE_VOL;
  251.         }
  252.  
  253. //        DebugFlex(f_MoveVol, "Vol");
  254.         ChangeSoundVol(n_MoveSoundChannel, f_MoveVol, UPDATE_MOVE_VOL_PULSE);
  255.  
  256.         f_MovePitch = (VEL_PITCH_MUL * f_MardukVelMag) + MIN_MOVE_PITCH;
  257.         if (f_MovePitch > MAX_MOVE_PITCH)
  258.         {
  259.             f_MovePitch = MAX_MOVE_PITCH;
  260.         }
  261.  
  262. //        DebugFlex(f_MovePitch, "Pitch");
  263.         ChangeSoundPitch(n_MoveSoundChannel, f_MovePitch, UPDATE_MOVE_VOL_PULSE);
  264.  
  265.     }
  266.     else
  267.     {
  268.         // Try again to get sound playing
  269.         n_MoveSoundChannel = PlaySoundThing(fly, t_Marduk, 1.0, 0.0, 20.0, 0x881);
  270.     }
  271.  
  272.     return;
  273.  
  274. # ........................................................................................
  275.  
  276. aievent:
  277.     if ( GetSenderRef() != t_Marduk ) return;
  278.     if (e_Mode == DO_NOTHING_MODE)
  279.     {
  280.         return;
  281.     }
  282.  
  283.     n_eventType        = GetParam(0);
  284. //    DebugFlex(n_eventType, "AIEVENT");
  285.  
  286.     if (n_eventType == 0x10000)        // SITHAI_EVENTPREFIRE
  287.     {
  288. //        DebugFlex(e_Mode, "PreFire");
  289.         // If not hovering, then don't fire
  290.         // However, because fire is delayed we will get another prefire
  291.         // when the correct key frame is reached, so allow firing while in firing mode
  292.         if ( ( (e_Mode != HOVERING_MODE) && (e_Mode != FIRING_MODE)) 
  293.              || !n_Ammo)
  294.         {
  295. //            DebugFlex(e_Mode, "Fire Aborted");
  296.             SetActorWeapon(t_Marduk, -1);
  297.         }
  298.     }
  299.     else if (n_eventType == 0x4000)        // SITHAI_EVENTFIRE
  300.     {
  301. //        DebugFlex(e_Mode, "Fire - Start Anim");
  302.         e_Mode = FIRING_MODE;
  303.         StopMode(t_Marduk, 65, 0.0);
  304.         n_Track = PlayMode(t_Marduk, 65, 0);
  305.         FadeInTrack(t_Marduk, n_Track, 0.5);
  306.         SetTimerEx(ATTACK_TIME, TIMER_ID_ATTACK_DONE, 0, 0);
  307.  
  308.     }
  309.     else if (n_eventType == 0x20000) // SITHAI_EVENTPOSTFIRE
  310.     {
  311. //        DebugFlex(e_Mode, "PostFire");
  312.         SetActorWeapon(t_Marduk, tpl_CrntWeapon);
  313.     }
  314.     else if (n_eventType == 0x800)// SITHAI_EVENTGOALREACHED
  315.     {
  316. //        DebugFlex(e_Mode, "Goal Reached");
  317.         if (e_Mode == MOVING_TO_CHARGING_POS_MODE)
  318.         {
  319.             call Charge; 
  320.         }
  321.         else if (e_Mode == MOVING_MODE)
  322.         {
  323.             e_Mode = HOVERING_NO_FIRE_MODE;
  324.             call Set_b_Low;
  325.  
  326.             // If not at attack height, move again immediately
  327.             if (b_MardukLow != b_AttackLow)
  328.             {
  329.                 call MoveToNewPosition;
  330.             }
  331.             // If at attack height, then move or attack after delay
  332.             else
  333.             {
  334.                 n_TempInt = RandBetween(1,100);
  335.     
  336.                 v_IndyPos = GetThingPos(t_Indy);
  337.                 v_MardukPos = GetThingPos(t_Marduk);
  338.  
  339.                 f_Dist = VectorDist(v_IndyPos, v_MardukPos);
  340.  
  341.                 // Must be outside min firing distance
  342.                 if ( (n_TempInt < 90) && (f_Dist > 0.35))
  343.                 {
  344. //                    PRINT("Fire Op");
  345.                     AISetSubMode(t_Marduk, 0x2000); // body tracking
  346.                     SetTimerEx(DELAY_BEFORE_ATTACK_AFTER_MOVE, TIMER_ID_ATTACK_OKAY, 0, 0);
  347.                 }
  348.                 else
  349.                 {
  350.                     call MoveToNewPosition;
  351.                 }
  352.             }
  353.         }
  354.         else if (e_Mode == FURY_MODE)
  355.         {
  356.             call MoveToNewPosition;
  357.         }
  358.     }
  359.     else if (n_eventType == 0x80000)// SITHAI_EVENTGOALUNREACHABLE
  360.     {
  361.         // Try again
  362.         call MoveToNewPosition;
  363.     }
  364.  
  365.     return;
  366.     
  367. blocked:                
  368. //    DebugPrint("Marduk Blocked");
  369.     if (e_Mode == DO_NOTHING_MODE)
  370.     {
  371.         return;
  372.     }
  373.     call MoveToNewPosition;
  374.     return;
  375.  
  376. # ........................................................................................
  377. // Damage indy on contact with marduk
  378. touched:
  379.     if (e_Mode == DO_NOTHING_MODE)
  380.     {
  381.         return;
  382.     }
  383.     if ( (GetSourceRef() == t_Indy)
  384.          && (GetSenderRef() == t_Marduk)
  385.          && b_OKToDamageIndy
  386.          )
  387.     {
  388. //        Print("Touched Indy");
  389.         DamageThing(t_Indy, 50, 0x00100000, t_Marduk);
  390.  
  391.         PlaySoundThing(shock, t_Indy, 1.0, 0.0, 10.0, 0x880);
  392.         v_MinLight = VectorSet(0.0, 0.0, 0.0);
  393.         v_MaxLight = VectorSet(1.0, 1.0, 1.0);
  394.         n_ShockLightAnim = ThingLightAnim(t_Marduk, v_MinLight, 20.0, v_MaxLight, 20.0, 0.025);
  395.         SetTimerEx(SHOCK_LIGHT_DURATION, TIMER_ID_STOP_SHOCK_LIGHT, 0, 0);
  396.         CreateThing(tpl_ChargeSparks, t_Indy);
  397.         
  398.         call MoveToNewPosition;
  399.         b_OKToDamageIndy=0;
  400.         Sleep(1.0); // so we don't damage him every frame
  401.         b_OKToDamageIndy=1;
  402.     }
  403.     
  404.     return;
  405.  
  406. # ........................................................................................
  407. damaged:
  408.     if (e_Mode == DO_NOTHING_MODE)
  409.     {
  410.         return;
  411.     }
  412.  
  413.     SetThingHealth(t_Marduk, GetThingMaxHealth(t_Marduk)); // heal that boy
  414.  
  415.     n_TempInt = GetParam(1); // damageclass
  416.     if (BITTEST(n_TempInt, 0x100000))
  417.     {
  418.         n_TimesBeenHit = n_TimesBeenHit + 1;
  419.         
  420.         // If maxed out then send user1 to other cog
  421.         if (n_TimesBeenHit == MAX_HITS)
  422.         {
  423. //            PRINT("Runaway");
  424.             e_Mode = DO_NOTHING_MODE;
  425.             SendMessageEx(Aet_MardukDias, 28, 0, 0, 0, 0);        
  426.             ReleaseThing(t_Marduk);
  427.             PlaySoundThing(defeat, t_Marduk, 1.0, 40.0, 40.0, 0x880);
  428.             if (n_MoveSoundChannel != -1)
  429.             {
  430.                 StopSound(n_MoveSoundChannel, 0.25);
  431.                 n_MoveSoundChannel = -1;
  432.                 SetPulse(0);
  433.             }
  434.             ReturnEx(0); 
  435.  
  436.         }
  437.         else if (n_TimesBeenHit < MAX_HITS)
  438.         {
  439.             e_Mode = FURY_MODE; // set to fury now so that he won't try to recharge before anim is done
  440.             SetTimerEX(FURY_START_DELAY, TIMER_ID_START_FURY, 0, 0);
  441.             PlaySoundThing(hurt, t_Marduk, 1.0, 40.0, 40.0, 0x880);
  442.             PlaySoundThing(shock, t_Marduk, 1.0, 40.0, 40.0, 0x880);
  443.             ReturnEx(20); // 20 will force him to play hit animation
  444.         }
  445.     }
  446.     else
  447.     {
  448.         if (BITTEST(GetParam(1), 0x1)) 
  449.         {
  450.             PlaySoundThing(rico, t_Marduk, 1.0, 20.0, 40.0, 0x880);
  451.         }
  452.         ReturnEx(0);
  453.     }
  454.  
  455.     return;
  456.  
  457.  
  458.  
  459. # ........................................................................................
  460.  
  461. timer:
  462.     n_TimerID = GetSenderID();
  463. //    DebugFlex(n_TimerID, "Timer");
  464.     if (n_TimerID == TIMER_ID_MOVE)
  465.     {
  466. //        DebugFlex(e_Mode, "Move Timer");
  467.         if (e_Mode == DO_NOTHING_MODE)
  468.         {
  469.             return;
  470.         }
  471.  
  472.         call MoveToNewPosition;
  473.     }
  474.     else if (n_TimerID == TIMER_ID_ATTACK_DONE)
  475.     {
  476. //        DebugFlex(n_Ammo, "AttackDone");
  477.  
  478.         if (e_Mode == DO_NOTHING_MODE)
  479.         {
  480.             return;
  481.         }
  482.  
  483.         n_Ammo = n_Ammo - 1;
  484.         SetActorWeapon(t_Marduk, tpl_CrntWeapon);
  485.  
  486.         if (e_Mode != FURY_MODE)
  487.         {
  488.             e_Mode = HOVERING_NO_FIRE_MODE;
  489.             SetTimerEx(AFTER_ATTACK_DELAY, TIMER_ID_REEVALUATE, 0, 0);
  490.         }
  491.     }
  492.     else if (n_TimerID == TIMER_ID_ATTACK_OKAY)
  493.     {
  494. //        DebugPrint("Attack Okay");
  495.         if (e_Mode == DO_NOTHING_MODE)
  496.         {
  497.             return;
  498.         }
  499.         e_Mode = HOVERING_MODE;
  500.         // Just in case attack doesn't happen
  501.         SetTimerEx(1.0, TIMER_ID_REEVALUATE, 0, 0);
  502.     }
  503.     else if (n_TimerID == TIMER_ID_START_LIGHTING)
  504.     {
  505. //        DebugPrint("Start Lightning");
  506.         
  507.         PlaySoundThing(chargeup, t_Marduk, 1.0, 20.0, 40.0, 0x880);
  508.  
  509.         SetTimerEX(0.0, TIMER_ID_CHARGE_SPARKS, 0, 0);
  510.  
  511.         v_LightningSrcOffset = VectorSet(0.0, 0.0, -0.15);
  512.         v_MardukPos = GetThingPos(t_Marduk);
  513.         v_Right = GetThingRVec(t_Marduk);
  514.         v_Up = GetThingUVec(t_Marduk);
  515.         
  516.         v_LightningEndPos = VectorAdd(v_MardukPos, VectorScale(v_Up, LIGHTNING_HEAD_DEST_UP_OFFSET));
  517.         CreateLightning(probe, v_LightningSrcOffset, v_LightningEndPos, LIGHTNING_BASE_RADIUS, LIGHTNING_TIP_RADIUS, LIGHTNING_DURATION);
  518.     
  519.         v_LightningEndPos = VectorAdd(v_MardukPos, VectorScale(v_Right, LIGHTNING_WING_DEST_RIGHT_OFFSET));
  520.         v_LightningEndPos = VectorAdd(v_LightningEndPos, VectorScale(v_Up, LIGHTNING_WING_DEST_UP_OFFSET));
  521.         CreateLightning(probe, v_LightningSrcOffset, v_LightningEndPos, LIGHTNING_BASE_RADIUS, LIGHTNING_TIP_RADIUS, LIGHTNING_DURATION);
  522.     
  523.         v_LightningEndPos = VectorAdd(v_MardukPos, VectorScale(v_Right, -LIGHTNING_WING_DEST_RIGHT_OFFSET));
  524.         v_LightningEndPos = VectorAdd(v_LightningEndPos, VectorScale(v_Up, LIGHTNING_WING_DEST_UP_OFFSET));
  525.         CreateLightning(probe, v_LightningSrcOffset, v_LightningEndPos, LIGHTNING_BASE_RADIUS, LIGHTNING_TIP_RADIUS, LIGHTNING_DURATION);
  526.  
  527.         // Das Blinkin Lites
  528.         v_MinLight = VectorSet(0.0, 0.0, 0.0);
  529.         v_MaxLight = VectorSet(1.0, 1.0, 1.0);
  530.         n_ProbeLightAnim = ThingLightAnim(probe, v_MinLight, 20.0, v_MaxLight, 20.0, 0.025);
  531.         SetTimerEx(LIGHTNING_DURATION, TIMER_ID_STOP_PROBE_LIGHT, 0, 0);
  532. //        DebugFlex(n_ProbLightAnim, "Start Probe Light");
  533.     }
  534.     else if (n_TimerID == TIMER_ID_STOP_PROBE_LIGHT)
  535.     {
  536. //        DebugPrint("Stop Probe Light");
  537.         if (n_ProbeLightAnim != -1)
  538.         {
  539.             StopAnim(n_ProbeLightAnim);
  540.             n_ProbeLightAnim = -1;
  541.             v_TempVec = VectorSet(0.0, 0.0, 0.0);
  542.             SetThingLight(probe, v_TempVec, 0.0, 0.0);
  543.         }
  544.     }
  545.     else if (n_TimerID == TIMER_ID_CHARGE_COMPLETE)
  546.     {
  547. //        DebugPrint("Charge Complete");
  548.         if (e_Mode == DO_NOTHING_MODE)
  549.         {
  550.             return;
  551.         }
  552.  
  553.         n_Ammo = MAX_AMMO;
  554.         e_Mode = HOVERING_NO_FIRE_MODE;
  555.         call MoveToNewPosition;
  556.     }
  557.     else if (n_TimerID == TIMER_ID_REEVALUATE)
  558.     {
  559. //        DebugFlex(e_Mode, "Re-evaluate");
  560.         if (e_Mode == DO_NOTHING_MODE)
  561.         {
  562.             return;
  563.         }
  564.  
  565.         if (e_Mode != FIRING_MODE)
  566.         {
  567. //            Print("Re-Evaluate");
  568.             if (!n_Ammo)
  569.             {
  570.                 call Charge;
  571.             }
  572.             else
  573.             {
  574.                 call MoveToNewPosition;
  575.             }
  576.         }
  577.     }
  578.     else if (n_TimerID == TIMER_ID_STOP_FURY)
  579.     {
  580. //        DebugPrint("Stop Fury");
  581.         if (e_Mode == DO_NOTHING_MODE)
  582.         {
  583.             return;
  584.         }
  585.         
  586.         e_Mode = MOVING_MODE;
  587.         
  588.         // Usually switch attach heights after fury
  589.         if (RandBetween(0,100) < 80)
  590.         {
  591.             if (b_AttackLow)
  592.             {
  593.                 b_AttackLow = 0;
  594.             }
  595.             else
  596.             {
  597.                 b_AttackLow = 1;
  598.             }
  599.         }
  600.     }
  601.     else if (n_TimerID == TIMER_ID_STOP_SHOCK_LIGHT)
  602.     {
  603. //        DebugPrint("Stop Probe Light");
  604.         if (n_ShockLightAnim != -1)
  605.         {
  606.             StopAnim(n_ShockLightAnim);
  607.             n_ShockLightAnim = -1;
  608.             v_TempVec = VectorSet(0.0, 0.0, 0.0);
  609.             SetThingLight(t_Marduk, v_TempVec, 0.0, 0.0);
  610.         }
  611.     }
  612.     else if (n_TimerID == TIMER_ID_START_FURY)
  613.     {
  614.         if (e_Mode == DO_NOTHING_MODE)
  615.         {
  616.             return;
  617.         }
  618.         call MoveToNewPosition;
  619.         SetTimerEX(FURY_DURATION, TIMER_ID_STOP_FURY, 0, 0);
  620.     }
  621.     else if (n_TimerID == TIMER_ID_CHARGE_SPARKS)
  622.     {
  623.         if (n_ProbeLightAnim != -1)
  624.         {
  625.             v_MardukPos = GetThingPos(t_Marduk);
  626.             v_MardukLook = GetThingLVec(t_Marduk);
  627.             v_MardukLook = VectorScale(v_MardukLook, 0.075);
  628.             v_LightningEndPos = VectorSet(VectorX(v_MardukLook), VectorY(v_MardukLook), VectorZ(v_MardukLook) + 0.1);
  629.             v_LightningEndPos = VectorAdd(v_LightningEndPos, v_MardukPos);
  630.             v_LightningEndPos = VectorAdd(VectorScale(RandVec(), 0.05), v_LightningEndPos);
  631.             CreateThingAtPos(tpl_ChargeSparks, FindNewSectorFromThing(t_Marduk, v_LightningEndPos), v_LightningEndPos, '0 0 0');
  632.             SetTimerEX(CHARGE_SPARK_DELAY, TIMER_ID_CHARGE_SPARKS, 0, 0);
  633.         }
  634.     }
  635.  
  636.     return;
  637.  
  638.  
  639. # ........................................................................................
  640. callback:
  641. //    DebugPrint("Callback");
  642. //    if ( (GetParam(1) == 21) && (e_Mode == WAITING_TO_MOVE_MODE))
  643. //    {
  644. //        call MoveToNewPosition;
  645. //    }
  646.  
  647.     return;
  648.  
  649. # ........................................................................................
  650. MoveToNewPosition:
  651. //    DebugPrint("MoveToNewPosition");
  652.     if (e_Mode == DO_NOTHING_MODE)
  653.     {
  654.         return;
  655.     }
  656.  
  657.     if ( (e_Mode == FIRING_MODE)
  658.          || (e_Mode == CHARGING_MODE)
  659.          )
  660.     {
  661. //        DebugPrint("Doh!!!");
  662. //        Print("Doh!!");
  663.         return;
  664.     }
  665.  
  666.     // Initialize stuff
  667.     v_IndyPos = GetThingPos(t_Indy);
  668.     v_MardukPos = GetThingPos(t_Marduk);
  669.  
  670.     call ComputeMardukOctant;
  671.     call ComputeIndyOctant;
  672.     call Set_b_Low;
  673.  
  674.     n_OctDist = n_MardukOctant - n_IndyOctant;
  675.  
  676.     if (n_OctDist > 4)
  677.     {
  678.         n_DirToIndy = 1; // clockwise
  679.     }
  680.     else if (n_OctDist > 0)
  681.     {
  682.         n_DirToIndy = -1; // counter clockwise
  683.     }
  684.     else if (n_OctDist == 0)
  685.     {
  686.         n_DirToIndy = 0; // same quadrant
  687.     }
  688.     else if (n_OctDist > -4)
  689.     {
  690.         n_DirToIndy = 1; // clockwise
  691.     }
  692.     else
  693.     {
  694.         n_DirToIndy = -1; // counter clockwise
  695.     }
  696. //    DebugFlex(n_DirToIndy, "Dir to Indy");
  697.  
  698.     if (e_Mode != FURY_MODE)
  699.     {
  700.         // In same octant as Indy
  701.         if (n_OctDist == 0)
  702.         {
  703.             if (b_MardukLow == b_IndyLow)
  704.             {
  705.                 // change altitude
  706.                 b_TempBool = 1;
  707.                 n_MaxOctChange = 1;
  708.             }
  709.             else
  710.             {
  711.                 // don't change altitude
  712.                 b_TempBool = 0;
  713.                 n_MaxOctChange = 3;
  714.             }
  715.         }
  716.         // Facing around circle towards Indy?
  717.         else if (n_DirToIndy == n_MardukFaceDir)
  718.         {
  719.             // If really close to Indy
  720.             if (Abs(n_OctDist) <= 1)
  721.             {
  722.                 // If close to Indy and on same level
  723.                 if (b_MardukLow == b_IndyLow)
  724.                 {
  725.                     // change altitude
  726.                     b_TempBool = 1;
  727.                     n_MaxOctChange = 2;
  728.                 }
  729.                 // If close to indy and not on same level
  730.                 else
  731.                 {
  732.                     // don't change altitude, change direction
  733.                     b_TempBool = 0;
  734.                     n_MaxOctChange = 3;
  735.                     n_MardukFaceDir = n_MardukFaceDir * -1.0;
  736.                 }
  737.             }
  738.             // If close to Indy, and facing him
  739.             else if (Abs(n_OctDist) <= 2)
  740.             {
  741.                 // If on attack level, lean toward staying on same level
  742.                 if (b_MardukLow == b_AttackLow)
  743.                 {
  744.                     if (RandBetween(0,100) < 10)
  745.                     {
  746.                         // change altitude
  747.                         b_TempBool = 1;
  748.                         n_MaxOctChange = 3;
  749.                     }
  750.                     else
  751.                     {
  752.                         // change direction not altitude
  753.                         b_TempBool = 0;
  754.                         n_MardukFaceDir = n_MardukFaceDir * -1.0;
  755.                         n_MaxOctChange = 3;
  756.                     }
  757.                 }
  758.                 // If not on attack level, lean toward changing level
  759.                 else
  760.                 {
  761.                     if (RandBetween(0,100) < 90)
  762.                     {
  763.                         // change altitude and direction
  764.                         b_TempBool = 1;
  765.                         n_MaxOctChange = 3;
  766.                         n_MardukFaceDir = n_MardukFaceDir * -1.0;
  767.                     }
  768.                     else
  769.                     {
  770.                         // change direction not altitude altitude
  771.                         b_TempBool = 0;
  772.                         n_MaxOctChange = 3;
  773.                         n_MardukFaceDir = n_MardukFaceDir * -1.0;
  774.                     }
  775.                 }
  776.             }
  777.             // If not too close to Indy, but facing him
  778.             else 
  779.             {
  780.                 // If on attack level, lean toward staying on same level
  781.                 if (b_MardukLow == b_AttackLow)
  782.                 {
  783.                     if (RandBetween(0,100) < 10)
  784.                     {
  785.                         // change altitude
  786.                         b_TempBool = 1;
  787.                         n_MaxOctChange = 3;
  788.                     }
  789.                     else
  790.                     {
  791.                         // don't change altitude
  792.                         b_TempBool = 0;
  793.                         n_MaxOctChange = Abs(n_OctDist) - 1;
  794.                     }
  795.                 }
  796.                 // If not on attack level, lean toward changing level
  797.                 else
  798.                 {
  799.                     if (RandBetween(0,100) < 90)
  800.                     {
  801.                         // change altitude
  802.                         b_TempBool = 1;
  803.                         n_MaxOctChange = Abs(n_OctDist) - 1;
  804.                     }
  805.                     else
  806.                     {
  807.                         // don't change altitude
  808.                         b_TempBool = 0;
  809.                         n_MaxOctChange = 3;
  810.                     }
  811.                 }
  812.             }
  813.         }
  814.         // Facing around circle away from Indy
  815.         else
  816.         {
  817.             // Lean toward staying on or moving to attack level
  818.             if (b_MardukLow == b_AttackLow)
  819.             {
  820.                 if (RandBetween(0,100) < 10)
  821.                 {
  822.                     // change altitude
  823.                     b_TempBool = 1;
  824.                     n_MaxOctChange = 3;
  825.                 }
  826.                 else
  827.                 {
  828.                     // don't change altitude
  829.                     b_TempBool = 0;
  830.                     n_MaxOctChange = 3;
  831.                 }
  832.             }
  833.             else
  834.             {
  835.                 if (RandBetween(0,100) < 90)
  836.                 {
  837.                     // change altitude
  838.                     b_TempBool = 1;
  839.                     n_MaxOctChange = 3;
  840.                 }
  841.                 else
  842.                 {
  843.                     // don't change altitude
  844.                     b_TempBool = 0;
  845.                     n_MaxOctChange = 3;
  846.                 }
  847.             }
  848.         }
  849.         // Figure out destination octant
  850.         //    DebugFlex(n_MaxOctChange, "MaxOctChange");
  851.         n_TempInt = RandBetween(1, n_MaxOctChange) * n_MardukFaceDir;
  852.         n_TempInt = n_TempInt + n_MardukOctant;
  853.  
  854.     }
  855.     // Fury Mode
  856.     else
  857.     {
  858.         b_TempBool = 0; // don't change altitude
  859.         n_TempInt = n_MardukFaceDir * 2;
  860.         n_TempInt = n_TempInt + n_MardukOctant;
  861.     }
  862.  
  863.     // Wrap octant destination number
  864.     if (n_TempInt > 7)
  865.     {
  866.         n_TempInt = n_TempInt - 8;
  867.     }
  868.     else if (n_TempInt < 0)
  869.     {
  870.         n_TempInt = n_TempInt + 8;
  871.     }
  872. //    DebugFlex(n_TempInt, "Dest Oct"); 
  873.  
  874.     v_TempVec = VectorScale(v_Oct0[n_TempInt], MARDUK_MOVE_RADIUS);
  875.     v_DestPos = VectorAdd(v_TempVec, v_BasePos);
  876.     
  877. //    DebugFlex(b_MardukLow, "Marduk Low");
  878. //    DebugFlex(VectorZ(v_MardukPos), "Marduk Z");
  879.     
  880.     // If new dest has high altitude
  881.     if (b_TempBool == b_MardukLow)
  882.     {
  883.         if (e_Mode == FURY_MODE)
  884.         {
  885.             f_TempFlex = HIGH_HEIGHT_ADJUST - (Rand() * 0.1);
  886.         }
  887.         else
  888.         {
  889.             f_TempFlex = HIGH_HEIGHT_ADJUST;
  890.         }
  891.     }
  892.     else
  893.     {
  894.         if (e_Mode == FURY_MODE)
  895.         {
  896.             f_TempFlex = (Rand() * 0.1);
  897.         }
  898.         else
  899.         {
  900.             f_TempFlex = 0.0;
  901.         }
  902.     }
  903.     v_DestPos = VectorSet(VectorX(v_DestPos), VectorY(v_DestPos), VectorZ(v_DestPos) + f_TempFlex);
  904.  
  905.     AISetMovePos(t_Marduk, v_DestPos, 0);
  906.     AISetLookPos(t_Marduk, v_DestPos);
  907.     AIClearSubMode(t_Marduk, 0x2000); // clear body tracking
  908.     
  909.     if (e_Mode != FURY_MODE)
  910.     {
  911.         e_Mode = MOVING_MODE;
  912.         AISetMoveSpeed(t_Marduk, DEFAULT_MOVE_SPEED);
  913.     }
  914.     else // FURY_MODE
  915.     {
  916.         AISetMoveSpeed(t_Marduk, FURY_MOVE_SPEED);
  917.     }
  918.  
  919.     return;
  920.  
  921.  
  922. # ........................................................................................
  923. MoveToChargingPos:
  924. //    DebugPrint("MoveToChargingPos");
  925.     e_Mode = MOVING_TO_CHARGING_POS_MODE;
  926.     AISetLookPos(t_Marduk, v_ChargingPos);
  927.     AISetMovePos(t_Marduk, v_ChargingPos, 0);
  928.     AIClearSubMode(t_Marduk, 0x2000); // body tracking
  929.     AISetMoveSpeed(t_Marduk, DEFAULT_MOVE_SPEED);
  930.  
  931.     return;
  932.  
  933. # ........................................................................................
  934. Charge:
  935. //    DebugPrint("Attempt Charging");
  936.  
  937.     // Make sure close enough to charge        
  938.     v_MardukPos = GetThingPos(t_Marduk);
  939.     f_Dist = VectorDist(v_MardukPos, v_ChargingPos);
  940.     if (f_Dist > 0.055)
  941.     {
  942.         call MoveToChargingPos;
  943.         return;
  944.     }
  945.  
  946.     AISetSubMode(t_Marduk, 0x2000); // body tracking
  947. //    DebugPrint("Charging");
  948.     e_Mode = CHARGING_MODE;
  949.     StopThing(t_Marduk);
  950.  
  951.     // Play charging anim
  952.     n_Track = PlayMode(t_Marduk, 60, 0);
  953.     FadeInTrack(t_Marduk, n_Track, 0.5);
  954.  
  955.     SetTimerEx(LIGHTNING_START_DELAY, TIMER_ID_START_LIGHTING, 0, 0);
  956.     SetTimerEx(CHARGE_DURATION, TIMER_ID_CHARGE_COMPLETE, 0, 0);
  957.  
  958.  
  959.     return;
  960.  
  961.  
  962. # ........................................................................................
  963. Set_b_Low:
  964.     v_MardukPos = GetThingPos(t_Marduk);
  965.     f_TempFlex = VectorZ(v_MardukPos) - VectorZ(v_BasePos);
  966.     if (f_TempFlex > 0.2)
  967.     {
  968.         b_MardukLow = 0;
  969.     }
  970.     else
  971.     {
  972.         b_MardukLow = 1;
  973.     }
  974.  
  975.     v_IndyPos = GetThingPos(t_Indy);
  976.     f_TempFlex = VectorZ(v_IndyPos) - VectorZ(v_BasePos);
  977.     if (f_TempFlex > 0.2)
  978.     {
  979.         b_IndyLow = 0;
  980.     }
  981.     else
  982.     {
  983.         b_IndyLow = 1;
  984.     }
  985.  
  986.     return;
  987.  
  988. # ........................................................................................
  989. #
  990. #           7 0
  991. #          6      1      
  992. #          5   2 
  993. #           4 3
  994. #
  995. ComputeMardukOctant:
  996.     // Initialize stuff
  997.     v_MardukPos = GetThingPos(t_Marduk);
  998.  
  999.     // Create flat Base to Marduk vector
  1000.     v_BaseToMarduk = VectorNorm(VectorSub(v_MardukPos, v_BasePos));
  1001.     v_BaseToMarduk = VectorSet(VectorX(v_BaseToMarduk), VectorY(v_BaseToMarduk), 0.0);
  1002.     v_BaseToMarduk = VectorNorm(v_BaseToMarduk);
  1003.  
  1004.     f_Dot = VectorDot(v_BaseToMarduk, v_North);
  1005.     f_Dot1 = VectorDot(v_BaseToMarduk, v_East);
  1006.     
  1007.     if (f_Dot > .707)
  1008.     {
  1009.         // most northern octants
  1010.         if (f_Dot1 > 0.0)
  1011.         {
  1012.             n_MardukOctant = 0;
  1013.         }
  1014.         else
  1015.         {
  1016.             n_MardukOctant = 7;
  1017.         }
  1018.     }
  1019.     else if (f_Dot > 0.0)
  1020.     {
  1021.         // northern octants to either side
  1022.         if (f_Dot1 > 0.0)
  1023.         {
  1024.             n_MardukOctant = 1;
  1025.         }
  1026.         else
  1027.         {
  1028.             n_MardukOctant = 6;
  1029.         }
  1030.     }
  1031.     else if (f_Dot > -.707)
  1032.     {
  1033.         // southern octants to either side
  1034.         if (f_Dot1 > 0.0)
  1035.         {
  1036.             n_MardukOctant = 2;
  1037.         }
  1038.         else
  1039.         {
  1040.             n_MardukOctant = 5;
  1041.         }
  1042.     }
  1043.     else
  1044.     {
  1045.         // most southern octants
  1046.         if (f_Dot1 > 0.0)
  1047.         {
  1048.             n_MardukOctant = 3;
  1049.         }
  1050.         else
  1051.         {
  1052.             n_MardukOctant = 4;
  1053.         }
  1054.     }
  1055.  
  1056.     v_Right = GetThingRVec(t_Marduk);
  1057.     f_Dot = VectorDot(v_BaseToMarduk, v_Right);
  1058.     if (f_Dot > 0.0)
  1059.     {
  1060.         n_MardukFaceDir  = -1 ; // counter clockwise
  1061.     }
  1062.     else
  1063.     {
  1064.         n_MardukFaceDir  = 1 ; // clockwise
  1065.     }
  1066.  
  1067. //    DebugFlex(n_MardukOctant, "Marduk Octant");
  1068. //    DebugFlex(n_MardukFaceDir, "Marduk Face Dir");
  1069.     return;
  1070.  
  1071. ComputeIndyOctant:
  1072.     // Initialize stuff
  1073.     v_IndyPos = GetThingPos(t_Indy);
  1074.  
  1075.     // Create flat Base to Marduk vector
  1076.     v_BaseToIndy = VectorNorm(VectorSub(v_IndyPos, v_BasePos));
  1077.     v_BaseToIndy = VectorSet(VectorX(v_BaseToIndy), VectorY(v_BaseToIndy), 0.0);
  1078.     v_BaseToIndy = VectorNorm(v_BaseToIndy);
  1079.  
  1080.     f_Dot = VectorDot(v_BaseToIndy, v_North);
  1081.     f_Dot1 = VectorDot(v_BaseToIndy, v_East);
  1082.     
  1083.     if (f_Dot > .707)
  1084.     {
  1085.         // most northern octants
  1086.         if (f_Dot1 > 0.0)
  1087.         {
  1088.             n_IndyOctant = 0;
  1089.         }
  1090.         else
  1091.         {
  1092.             n_IndyOctant = 7;
  1093.         }
  1094.     }
  1095.     else if (f_Dot > 0.0)
  1096.     {
  1097.         // northern octants to either side
  1098.         if (f_Dot1 > 0.0)
  1099.         {
  1100.             n_IndyOctant = 1;
  1101.         }
  1102.         else
  1103.         {
  1104.             n_IndyOctant = 6;
  1105.         }
  1106.     }
  1107.     else if (f_Dot > -.707)
  1108.     {
  1109.         // southern octants to either side
  1110.         if (f_Dot1 > 0.0)
  1111.         {
  1112.             n_IndyOctant = 2;
  1113.         }
  1114.         else
  1115.         {
  1116.             n_IndyOctant = 5;
  1117.         }
  1118.     }
  1119.     else
  1120.     {
  1121.         // most southern octants
  1122.         if (f_Dot1 > 0.0)
  1123.         {
  1124.             n_IndyOctant = 3;
  1125.         }
  1126.         else
  1127.         {
  1128.             n_IndyOctant = 4;
  1129.         }
  1130.     }
  1131.  
  1132. //    DebugFlex(n_IndyOctant, "Indy Octant");
  1133.  
  1134.     return;
  1135.  
  1136. end
  1137.  
  1138.